﻿using System;
using UnityEngine;

namespace ZFramework.Runtime.WebRequest
{
    /// <summary>
    /// Web 请求管理器。
    /// </summary>
    public sealed partial class WebRequestManager : FrameworkManagerBase, IWebRequestManager
    {
        private TaskPool<WebRequestTask> m_TaskPool;
        private IEventManager _eventMgr;
        
        [SerializeField]
        private Transform m_InstanceRoot = null;
        
        [SerializeField]
        private string m_WebRequestAgentHelperTypeName = "ZFramework.Runtime.WebRequest.UnityWebRequestAgentHelper";
        
        [SerializeField]
        private WebRequestAgentHelperBase m_CustomWebRequestAgentHelper = null;
        
        [SerializeField]
        private int m_WebRequestAgentHelperCount = 1;
        
        [SerializeField]
        private float m_Timeout = 30f;

        protected override void Awake()
        {
            base.Awake();
            m_TaskPool = new TaskPool<WebRequestTask>();
            m_Timeout = 30f;
        }

        /// <summary>
        /// 初始化 Web 请求管理器的新实例。
        /// </summary>
        void Start()
        {
            if (m_InstanceRoot == null)
            {
                m_InstanceRoot = new GameObject("WebRequest Agent Instances").transform;
                m_InstanceRoot.SetParent(transform);
                m_InstanceRoot.localScale = Vector3.one;
            }
            
            _eventMgr = FrameworkManagerManager.GetManager<EventManager>();
            if (string.IsNullOrEmpty(m_WebRequestAgentHelperTypeName))
            {
                throw new FrameworkException("WebRequestManager 必须先设置 _agentHelperName");
            }

            for (int i = 0; i < m_WebRequestAgentHelperCount; i++)
            {
                var helperGo = new GameObject($"WebRequestAgentHelper-{i}");
                var trans = helperGo.transform;
                trans.SetParent(m_InstanceRoot);
                Type helperType = Utility.Assembly.GetType(m_WebRequestAgentHelperTypeName);
                if (helperType == null)
                {
                    Log.Error("WebRequestManager is invalid1.  name=={0}", m_WebRequestAgentHelperTypeName);
                    return;
                }
                var helper = (IWebRequestAgentHelper)helperGo.AddComponent(helperType);
                if (helper == null)
                {
                    Log.Error("WebRequestManager is invalid2.  name=={0}", m_WebRequestAgentHelperTypeName);
                    return;
                }
                AddWebRequestAgentHelper(helper);
            }
        }
        
        /// <summary>
        /// Web 请求管理器轮询。
        /// </summary>
        /// <param name="elapseSeconds">逻辑流逝时间，以秒为单位。</param>
        /// <param name="realElapseSeconds">真实流逝时间，以秒为单位。</param>
        public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            m_TaskPool.Update(elapseSeconds, realElapseSeconds);
        }

        /// <summary>
        /// 关闭并清理 Web 请求管理器。
        /// </summary>
        public override void Shutdown()
        {
            m_TaskPool.Shutdown();
        }

        /// <summary>
        /// 获取 Web 请求代理总数量。
        /// </summary>
        public int TotalAgentCount
        {
            get
            {
                return m_TaskPool.TotalAgentCount;
            }
        }

        /// <summary>
        /// 获取可用 Web 请求代理数量。
        /// </summary>
        public int FreeAgentCount
        {
            get
            {
                return m_TaskPool.FreeAgentCount;
            }
        }

        /// <summary>
        /// 获取工作中 Web 请求代理数量。
        /// </summary>
        public int WorkingAgentCount
        {
            get
            {
                return m_TaskPool.WorkingAgentCount;
            }
        }

        /// <summary>
        /// 获取等待 Web 请求数量。
        /// </summary>
        public int WaitingTaskCount
        {
            get
            {
                return m_TaskPool.WaitingTaskCount;
            }
        }

        /// <summary>
        /// 获取或设置 Web 请求超时时长，以秒为单位。
        /// </summary>
        public float Timeout
        {
            get
            {
                return m_Timeout;
            }
            set
            {
                m_Timeout = value;
            }
        }

        /// <summary>
        /// 增加 Web 请求代理辅助器。
        /// </summary>
        /// <param name="webRequestAgentHelper">要增加的 Web 请求代理辅助器。</param>
        private void AddWebRequestAgentHelper(IWebRequestAgentHelper webRequestAgentHelper)
        {
            WebRequestAgent agent = new WebRequestAgent(webRequestAgentHelper);
            agent.WebRequestAgentStart += OnWebRequestAgentStart;
            agent.WebRequestAgentSuccess += OnWebRequestAgentSuccess;
            agent.WebRequestAgentFailure += OnWebRequestAgentFailure;

            m_TaskPool.AddAgent(agent);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri)
        {
            return AddWebRequest(webRequestUri, null, Constant.DefaultPriority, null);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="postData">要发送的数据流。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, byte[] postData)
        {
            return AddWebRequest(webRequestUri, postData, Constant.DefaultPriority, null);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="priority">Web 请求任务的优先级。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, int priority)
        {
            return AddWebRequest(webRequestUri, null, priority, null);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="userData">用户自定义数据。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, object userData)
        {
            return AddWebRequest(webRequestUri, null, Constant.DefaultPriority, userData);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="postData">要发送的数据流。</param>
        /// <param name="priority">Web 请求任务的优先级。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, byte[] postData, int priority)
        {
            return AddWebRequest(webRequestUri, postData, priority, null);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="postData">要发送的数据流。</param>
        /// <param name="userData">用户自定义数据。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, byte[] postData, object userData)
        {
            return AddWebRequest(webRequestUri, postData, Constant.DefaultPriority, userData);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="priority">Web 请求任务的优先级。</param>
        /// <param name="userData">用户自定义数据。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, int priority, object userData)
        {
            return AddWebRequest(webRequestUri, null, priority, userData);
        }

        /// <summary>
        /// 增加 Web 请求任务。
        /// </summary>
        /// <param name="webRequestUri">Web 请求地址。</param>
        /// <param name="postData">要发送的数据流。</param>
        /// <param name="priority">Web 请求任务的优先级。</param>
        /// <param name="userData">用户自定义数据。</param>
        /// <returns>新增 Web 请求任务的序列编号。</returns>
        public int AddWebRequest(string webRequestUri, byte[] postData, int priority, object userData)
        {
            if (string.IsNullOrEmpty(webRequestUri))
            {
                throw new Exception("Web request uri is invalid.");
            }

            if (TotalAgentCount <= 0)
            {
                throw new Exception("You must add web request agent first.");
            }

            WebRequestTask webRequestTask = WebRequestTask.Create(webRequestUri, postData, priority, m_Timeout, userData);
            m_TaskPool.AddTask(webRequestTask);
            return webRequestTask.SerialId;
        }

        public int AddWebRequest(string webRequestUri, byte[] postData, string contentType, int priority,
            object userData)
        {
            return AddWebRequest(webRequestUri, postData, priority, WebRequestContentInfo.Create(contentType, userData));
        }


        /// <summary>
        /// 移除 Web 请求任务。
        /// </summary>
        /// <param name="serialId">要移除 Web 请求任务的序列编号。</param>
        /// <returns>是否移除 Web 请求任务成功。</returns>
        public bool RemoveWebRequest(int serialId)
        {
            return m_TaskPool.RemoveTask(serialId);
        }

        /// <summary>
        /// 移除所有 Web 请求任务。
        /// </summary>
        public void RemoveAllWebRequests()
        {
            m_TaskPool.RemoveAllTasks();
        }

        /// <summary>
        /// 获取所有 Web 请求任务的信息。
        /// </summary>
        /// <returns>所有 Web 请求任务的信息。</returns>
        public TaskInfo[] GetAllWebRequestInfos()
        {
            return m_TaskPool.GetAllTaskInfos();
        }

        private void OnWebRequestAgentStart(WebRequestAgent sender)
        {
            WebRequestStartEventArgs webRequestStartEventArgs = WebRequestStartEventArgs.Create(sender.Task.SerialId, sender.Task.WebRequestUri, sender.Task.UserData);
            _eventMgr.Fire(this, webRequestStartEventArgs);
        }

        private void OnWebRequestAgentSuccess(WebRequestAgent sender, byte[] webResponseBytes)
        {
            WebRequestSuccessEventArgs webRequestSuccessEventArgs = WebRequestSuccessEventArgs.Create(sender.Task.SerialId, sender.Task.WebRequestUri, webResponseBytes, sender.Task.UserData);
            _eventMgr.Fire(this, webRequestSuccessEventArgs);
        }

        private void OnWebRequestAgentFailure(WebRequestAgent sender, string errorMessage)
        {
            WebRequestFailureEventArgs webRequestFailureEventArgs = WebRequestFailureEventArgs.Create(sender.Task.SerialId, sender.Task.WebRequestUri, errorMessage, sender.Task.UserData);
            _eventMgr.Fire(this, webRequestFailureEventArgs);
        }
    }
}
